/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.legendframework.dao.support;

import com.legendframework.dao.annotation.Column;
import com.legendframework.dao.SFunction;
import com.legendframework.dao.exception.DaoException;
import com.legendframework.dao.utils.DaoStringUtils;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.Locale.ENGLISH;

/**
 * Lambda 解析工具类
 *
 * @author HCL
 * @since 2018-05-10
 */
public final class LambdaUtils {

    private static final Map<String, Map<String, ColumnCache>> LAMBDA_CACHE = new ConcurrentHashMap<>();

    /**
     * SerializedLambda 反序列化缓存
     */
    private static final Map<Class, WeakReference<SerializedLambda>> FUNC_CACHE = new ConcurrentHashMap<>();

    /**
     * 解析 lambda 表达式
     *
     * @param func 需要解析的 lambda 对象
     * @param <T>  类型，被调用的 Function 对象的目标类型
     * @return 返回解析后的结果
     */
    public static <T> SerializedLambda resolve(SFunction<T, ?> func) {
        Class clazz = func.getClass();
        return Optional.ofNullable(FUNC_CACHE.get(clazz))
            .map(WeakReference::get)
            .orElseGet(() -> {
                SerializedLambda lambda = SerializedLambda.resolve(func);
                FUNC_CACHE.put(clazz, new WeakReference<>(lambda));
                return lambda;
            });
    }


    /**
     * 获取实体对应字段 MAP
     *
     * @param entityClassName 实体类名
     * @return 缓存 map
     */
    public static Map<String, ColumnCache> getColumnMap(String entityClassName) {
        Map<String, ColumnCache> cacheMap = LAMBDA_CACHE.get(entityClassName);
        if (cacheMap != null) {
            return cacheMap;
        }
        cacheMap = new HashMap<>();
        Class<?> entityClass;
        try {
            entityClass = Class.forName(entityClassName);
        } catch (ClassNotFoundException e) {
            throw new DaoException("实体类找不到: "+entityClassName, e);
        }
        List<Field> fields = ClassUtils.getByClass(entityClass);
        for (Field field : fields) {
            ColumnCache columnCache = new ColumnCache();
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                if (!column.exist()) {
                    continue;
                }
                if (DaoStringUtils.isNotEmpty(column.value())){
                    columnCache.setColumn(field.getAnnotation(Column.class).value());
                }
            } else {
                columnCache.setColumn(field.getName());
            }
            cacheMap.put(field.getName().toUpperCase(ENGLISH),columnCache);
        }
        return cacheMap;
    }


}
